package be.nepherte.movmanager.client.ui;

import java.util.List;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

import be.nepherte.movmanager.client.MovManager;
import be.nepherte.movmanager.client.services.MovieService;
import be.nepherte.movmanager.client.services.MovieServiceAsync;
import be.nepherte.movmanager.client.exceptions.InvalidMovieException;
import be.nepherte.movmanager.client.ui.components.MessagePopupPanel;
import be.nepherte.movmanager.client.ui.components.MovieGrid;
import be.nepherte.movmanager.client.ui.tabframework.Tab;
import be.nepherte.movmanager.domain.Movie;
import be.nepherte.movmanager.domain.UserInfo;

/**
 * This class represents the Add Movie tab of MovManager. This page allows the
 * user to add a movie in his/her movie collection.
 * 
 * <p>
 * Copyright © 2010 Bart Verhoeven
 * </p>
 * 
 * <p>
 * This file is part of MovManager.
 * </p>
 * 
 * <p>
 * MovManager is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * </p>
 * 
 * <p>
 * MovManager is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * </p>
 * 
 * <p>
 * You should have received a copy of the GNU General Public License along with
 * MovManager. If not, see http://www.gnu.org/licenses/.
 * </p>
 * 
 * @author 	Bart Verhoeven
 * @version	0.1
 */
public class AddMovieTab extends Tab implements ClickHandler {
	/**Content panel.*/
	private final VerticalPanel contentPanel = new VerticalPanel();
	/**Button panel.*/
	private final HorizontalPanel btnPanel = new HorizontalPanel();
	/**Movie grid.*/
	private final MovieGrid movieGrid = new MovieGrid();
	/**Send button.*/
	private final Button btnAdd = new Button(MovManager.constants.buttonAdd(), this);
	/**Cancel button.*/
	private final Button btnCancel = new Button(MovManager.constants.buttonCancel(), this);
	/**Movie service.*/
	private final MovieServiceAsync movieService = GWT.create(MovieService.class);
	/**User info of the current user.*/
	private final UserInfo userInfo;
	
	 /**
     * Creates, initializes and return InfoTab.
     * 
     * @param	userInfo
     * 			user info of the current user
     */
	public static TabInfo init(final UserInfo userInfo) {
		
		
		return new TabInfo(MovManager.constants.addMovieTabName(), MovManager.constants.addMovieTabDescription(), MovManager.constants.addMovieTabColor()) {	
			@Override
			public Tab createInstance() {
				return new AddMovieTab(userInfo);
			}
		};
	}
	
	/**
	 * Creates a new AddMovieTab. To create an object of this class, use
	 * {@link #init()}.
	 * 
	 * @param	userInfo
	 * 			the user info of the current user
	 */
	private AddMovieTab(UserInfo userInfo) {
		super();
		this.userInfo = userInfo;
		initButtonPanel();
		initContentPanel();
	}
	
	/**
	 * Initializes the content panel with the actual content.
	 */
	private void initContentPanel() {
		formatContentPanel();
		contentPanel.add(movieGrid);
		contentPanel.add(btnPanel);
		initWidget(contentPanel);
	}
	/**
	 * Formats the content panel: apply correct spacing and alignment.
	 */
	private void formatContentPanel() {
		contentPanel.setSpacing(5);
		contentPanel.setHorizontalAlignment(VerticalPanel.ALIGN_CENTER);
	}
	
	/**
	 * Initializes the button panel with the cancel and send button.
	 */
	private void initButtonPanel() {
		formatButtonPanel();
		btnPanel.add(btnCancel);
		btnPanel.add(btnAdd);
	}
	
	/**
	 * Formats the button panel: apply correct button sizes and spacing.
	 */
	private void formatButtonPanel() {
		btnAdd.setWidth("50px");
		btnCancel.setWidth("60px");
		btnPanel.setSpacing(5);
	}

	
	/**
	 * Specifies what happens upon hiding this page: the movie grid is cleared.
	 */
	@Override
	public void onHide() {
		movieGrid.reset();
	}

	@Override
	public void onShow() {
	}
	
	/**
	 * Stores the movie that is currently in the movie grid in the database. Displays
	 * error messages next to the cause when the movie is not valid.
	 */
	private void storeMovie() {
		final Movie movie;
		
		try {
			movie = movieGrid.getMovie();
		} catch (InvalidMovieException e) {
			return;
		}

		AsyncCallback<Movie> callback = new AsyncCallback<Movie>() {
			@Override
			public void onFailure(Throwable caught) {
					MessagePopupPanel pp = new MessagePopupPanel(caught.getMessage(), "ppError");
					pp.show();
			}

			@Override
			public void onSuccess(Movie result) {
				MessagePopupPanel pp = new MessagePopupPanel("The movie " + movie.getTitle() + " is created", "ppSuccess");
				pp.show();
				List<Movie> movies = userInfo.getMovies();
				movies.add(result);
				userInfo.setMovies(movies);

			}
		};
		movieService.storeMovie(movie, userInfo, callback);
	}
	
	
	/**
	 * Called when a click event is fired by one of the clickable components in
	 * this tab.
	 */
	@Override
	public void onClick(ClickEvent event) {
		Widget sender = (Widget) event.getSource();
		
		// send button has been clicked
		if (sender.equals(btnAdd)) {
			storeMovie();
			return;
		}
		
		// cancel button has been clicked
		if (sender.equals(btnCancel)) {
			movieGrid.reset();
			return;
		}
	}
}